using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class LazyDynamicGrammarSpecification {
        [Test]
        public void ChangesToProductionsInPushedLanguageShouldNotAffectProductionsInOriginal () {
            var grammar = new LazyDynamicGrammar ();
            var p1 = new Mock<IProduction> ().Object;
            grammar.AddDynamicChoice ("p1", new[] {p1});
            var p2 = new Mock<IProduction> ().Object;
            grammar.AddDynamicChoice ("p2", new [] { p2 });

            var newGrammar = grammar.Clone ();

            var p3 = new Mock<IProduction> ().Object;
            newGrammar.AddDynamicChoice ("p3", new [] { p3 });

            Assert.That (newGrammar.HasDynamicChoice ("p1"));
            Assert.That (newGrammar.HasDynamicChoice ("p2"));
            Assert.That (newGrammar.HasDynamicChoice ("p3"));

            Assert.That (grammar.HasDynamicChoice ("p1"));
            Assert.That (grammar.HasDynamicChoice ("p2"));
            Assert.That (!grammar.HasDynamicChoice ("p3"));
        }

        [Test]
        public void ChangesToProductionInPushedLanguageShouldNotAffectProductionInOriginal () {
            var grammar = new LazyDynamicGrammar ();
            var p1 = new Mock<IProduction> ().Object;
            var p2 = new Mock<IProduction> ().Object;
            grammar.AddDynamicChoice ("p1", new [] {p1, p2});

            var newGrammar = grammar.Clone ();

            var p3 = new Mock<IProduction> ().Object;
            newGrammar.InsertChoiceBefore ("p1", p2, p3);

            Assert.That (newGrammar.GetChoices ("p1"), Is.EqualTo (new[] {p1, p3, p2}));

            Assert.That (grammar.GetChoices ("p1"), Is.EqualTo (new [] { p1, p2 }));
        }

        [Test]
        public void AddDynamicChoiceShouldGetChoicesForSameKey () {
            var grammar = new LazyDynamicGrammar ();

            IProduction p1 = new Mock<IProduction> ().Object;
            IProduction p2 = new Mock<IProduction> ().Object;
            IProduction p3 = new Mock<IProduction> ().Object;
            grammar.AddDynamicChoice (1, new [] { p1, p2 });
            grammar.AddDynamicChoice (2, new [] { p3 });

            Assert.That (grammar.GetChoices (1), Is.EqualTo (new [] { p1, p2 }));
            Assert.That (grammar.GetChoices (2), Is.EqualTo (new [] { p3 }));
        }

        [Test]
        public void ShouldThrowExceptionIfChoicesKeyNotFound () {
            Assert.Throws<KeyNotFoundException> (() => new LazyDynamicGrammar ().GetChoices (1));
        }
    }
}